﻿using Daq.Utils;
using MessagePack;
using MessagePack.Formatters;
using Microsoft.Win32;
using Parquet;
using Parquet.Data;
using Parquet.Schema;
using Parquet.Utils;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using KeyAttribute = MessagePack.KeyAttribute;

namespace Daq.Services
{
    public enum TriggerType
    {
        [Display(Name = "无")]
        None,
        [Display(Name = "=")]
        Equal,
        [Display(Name = ">")]
        GreaterThan,
        [Display(Name = "≥")]
        GreaterEqual,
        [Display(Name = "＜")]
        LessThan,
        [Display(Name = "≤")]
        LessEqual
    }

    public enum Logic
    {
        [Display(Name = "无")]
        None,
        [Display(Name = "与")]
        And,
        [Display(Name = "或")]
        Or
    }

    [MessagePackObject]
    public class TriggerInfo
    {
        [Key(0)]
        public TriggerType Type1 { get; set; }
        [Key(1)]
        public int Value1 { get; set; }
        [Key(2)]
        public Logic Logic { get; set; }
        [Key(3)]
        public TriggerType Type2 { get; set; }
        [Key(4)]
        public int Value2 { get; set; }
    }

    [MessagePackObject]
    public struct ChannelInfo
    {
        [Key(0)]
        public string Name { get; set; }
        [Key(1)]
        public string Unit { get; set; }
        [Key(2)]
        public int Digits { get; set; }
        [Key(3)]
        public TriggerInfo Trigger { get; set; }
    }

    [MessagePackObject]
    public class ChannelProperty
    {
        [Key(0)]
        public double Average { get; set; }
        [Key(1)]
        public long Sum { get; set; }
        [Key(2)]
        public int Min { get; set; }
        [Key(3)]
        public int Max { get; set; }
        [Key(4)]
        public int TriggerCount { get; set; }
        [Key(5)]
        public int SampleCount {  get; set; }
    }

    [MessagePackObject]
    public class DataProperty
    {
        [Key(0)]
        public List<ChannelInfo> Channels { get; set; } = [];
        [Key(1)]
        public DateTime StartTime { get; set; }
    }

    [MessagePackObject]
    public class ChannelMetaData
    {
        [Key(0)]
        public ChannelInfo Info { get; set; }
        [Key(1)]
        public List<ChannelProperty> Properties { get; set; } = [];
    }

    public class DateTimeKindPreservingFormatter : IMessagePackFormatter<DateTime>
    {
        public void Serialize(ref MessagePackWriter writer, DateTime value, MessagePackSerializerOptions options)
        {
            // 序列化时同时保存 Ticks 和 Kind
            writer.WriteArrayHeader(2);
            writer.Write(value.Ticks);
            writer.Write(value.Kind.ToString());
        }

        public DateTime Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
        {
            // 反序列化时恢复 Ticks 和 Kind
            if (reader.TryReadNil())
            {
                return default;
            }

            var length = reader.ReadArrayHeader();
            if (length != 2)
            {
                throw new InvalidOperationException("DateTime format error");
            }

            var ticks = reader.ReadInt64();
            var kindStr = reader.ReadString();
            if (!Enum.TryParse<DateTimeKind>(kindStr, out var kind))
            {
                kind = DateTimeKind.Unspecified;
            }

            return new DateTime(ticks, kind);
        }
    }

    [MessagePackObject]
    public class MetaData
    {
        [Key(0)]
        [MessagePackFormatter(typeof(DateTimeKindPreservingFormatter))]
        public DateTime StartTime { get; set; }
        [Key(1)]
        public List<ChannelMetaData>? Channels { get; set; }
        [Key(2)]
        public int SamplesPerSecond { get; set; }
    }

    public struct DataInfo
    {
        // 创建时间
        public DateTime StartTime { get; private set; }

        // 每个块的数据条数
        public int BlockSize { get; set; }

        // 统计块的个数
        public int BlockFileCount { get; set; }

        // 每天的块数
        public int DayBlockSize => 60 * 24;

        // 统计按天合并的文件个数
        public int DayFileCount { get; set; }

        //通道数
        public int ChannelCount { get; set; }

        // 数据属性
        public DataProperty DataProperty { get; set; }

        // 元数据
        public MetaData MetaData { get; set; }

        public DataInfo(int samplesPerSecond, List<ChannelInfo> channels)
        {
            StartTime = DateTime.Now;
            BlockSize = samplesPerSecond * 60;
            ChannelCount = channels.Count;
            DataProperty = new();
            DataProperty.Channels = channels;
            MetaData = new()
            {
                StartTime = StartTime,
                SamplesPerSecond = samplesPerSecond,
                Channels = channels.Select(ch => new ChannelMetaData
                {
                    Info = new ChannelInfo
                    {
                        Name = ch.Name,
                        Unit = ch.Unit,
                        Digits = ch.Digits,
                        Trigger = ch.Trigger,
                    },
                    Properties = []
                }).ToList()
            };
        }
    }
    public interface IDataService
    {
        void Start(int samplesPerSecond, List<ChannelInfo> channels, string rootDirectory, string? filePrefix = "");
        Task AppendData(ulong time, int[] values);
        void Stop();
        Task<List<string>?> ListAllDataFiles(string dir);
        Task<MetaData?> ReadMetaData(string path);
        Task<double[]?> GetTriggerCounts(string? dir, string? channelName, TriggerInfo info);
        Task<double[]?> Query(string? dir, string channelName, int blockStart, int blockEnd, MetaData? metadata = null);
        Task CopyFileAsyncWithProgress(string sourcePath, string destinationPath, IProgress<double>? progress = null);
        double[] DownSampleArray(double[] rawData, int targetSize);
        Task ExportData(string dir, List<string> channelNames, int startMinute, int endMinute);
    }
    public class DataService : IDataService
    {
        private const string extName = ".dxd";
        //private List<ConcurrentQueue<int>>? buffer;
        private List<Channel<int>>? buffer;
        private ConcurrentQueue<ulong>? times;
        private string rootDirectory;
        //private string currentFileDirectory;
        private string? filePrefix;
        private static readonly CompressionMethod compressionMethod = CompressionMethod.Snappy;
        //private MetaData metadata = new();
        private static DataInfo dataInfo;

        private string currentTempFileDirectory => Path.Combine(rootDirectory, $@"{filePrefix}{dataInfo.StartTime:yyyyMMdd-HHmmss}/{dataInfo.DayFileCount:D4}/");
        private string currentFilePath => Path.Combine(rootDirectory, $@"{filePrefix}{dataInfo.StartTime:yyyyMMdd-HHmmss}/{dataInfo.DayFileCount:D4}{extName}");
        private string currentTempFilePath => Path.Combine(currentTempFileDirectory, $"{dataInfo.BlockFileCount:D6}{extName}.tmp");
        private string propertyFilePath => Path.Combine(currentTempFileDirectory, ".properties");

        private bool firstData = true;
        private DateTime? startTime;
        private TriggerInfo[]? triggers;
        private int[] triggerCounts = [];
        private readonly IDialogService dialogService;
        public DataService(IDialogService dialogService)
        {
            this.dialogService = dialogService;
        }
        public async Task AppendData(ulong time, int[] values)
        {
            if (buffer == null || times == null)
            {
                return;
            }
            var count = values.Length;
            if (count != dataInfo.ChannelCount)
            {
                throw new Exception($"传入的数据通道数{count}不正确");
            }

            if (firstData)
            {
                firstData = false;
                startTime = DateTime.Now;
            }

            times.Enqueue(time);
            for (int i = 0; i < count; i++)
            {
                await buffer[i].Writer.WriteAsync(values[i]);
            }
        }
        private static int AssessBlockSize(int samplesPerSecond)
        {
            return samplesPerSecond * 60;
        }

        private CancellationTokenSource? cancellationTokenSource;
        public void Stop()
        {
            cancellationTokenSource?.Cancel();
        }

        public void Start(int samplesPerSecond, List<ChannelInfo> channels, string rootDirectory, string? filePrefix = "")
        {
            if (string.IsNullOrWhiteSpace(rootDirectory))
            {
                throw new Exception("根文件夹不能为空");
            }
            if(samplesPerSecond <= 0)
            {
                throw new Exception($"采样率参数\"{samplesPerSecond}\"不正确");
            }
            this.rootDirectory = rootDirectory;
            dataInfo = new(samplesPerSecond, channels);
            triggers = channels.Select(ch => ch.Trigger).ToArray();
            triggerCounts = new int[channels.Count];
            buffer = Enumerable.Range(0, channels.Count).Select(i => Channel.CreateUnbounded<int>()).ToList();
            times = [];

            if (string.IsNullOrWhiteSpace(filePrefix))
            {
                filePrefix = "DATA";
            }
            this.filePrefix = filePrefix;
            cancellationTokenSource = new();
            Task.Factory.StartNew(() => DataWriteTask(cancellationTokenSource.Token), TaskCreationOptions.LongRunning);
        }

        private bool IsTriggered(int value, TriggerInfo triggerInfo)
        {
            if (triggerInfo == null) return false;
            bool result1 = triggerInfo.Type1 switch
            {
                TriggerType.None => false,
                TriggerType.Equal => value == triggerInfo.Value1,
                TriggerType.GreaterThan => value > triggerInfo.Value1,
                TriggerType.GreaterEqual => value >= triggerInfo.Value1,
                TriggerType.LessThan => value < triggerInfo.Value1,
                TriggerType.LessEqual => value <= triggerInfo.Value1,
                _ => throw new NotImplementedException()
            };

            if (triggerInfo.Logic == Logic.None)
            {
                return result1;
            }

            if (result1 == true)
            {
                if (triggerInfo.Logic == Logic.Or)
                {
                    return true;
                }
            }
            else
            {
                if (triggerInfo.Logic == Logic.And)
                {
                    return false;
                }
            }

            bool result2 = triggerInfo.Type2 switch
            {
                TriggerType.None => false,
                TriggerType.Equal => value == triggerInfo.Value2,
                TriggerType.GreaterThan => value > triggerInfo.Value2,
                TriggerType.GreaterEqual => value >= triggerInfo.Value2,
                TriggerType.LessThan => value < triggerInfo.Value2,
                TriggerType.LessEqual => value <= triggerInfo.Value2,
                _ => throw new NotImplementedException()
            };

            if (triggerInfo.Logic == Logic.And)
            {
                return result1 && result2;
            }
            return result1 || result2;
        }
        public async Task<List<string>?> ListAllDataFiles(string dir)
        {
            //if (!Directory.Exists(dir))
            //{
            //    Directory.CreateDirectory(dir);
            //    return null;
            //}
            //return await Task.Run(() =>
            //{
            //    List<string> names = new List<string>();
            //    DirectoryInfo directoryInfo = new(dir);
            //    foreach (DirectoryInfo item in directoryInfo.Enu("*", SearchOption.TopDirectoryOnly))
            //    {
            //        var files = item.EnumerateFiles($"*{extName}", SearchOption.TopDirectoryOnly);
            //        if (files == null || files.Count() == 0)
            //        {
            //            continue;
            //        }
            //        names.Add(item.Name);
            //    }
            //    return names;
            //});
            return null;
        }
        private async Task DataWriteTask(CancellationToken token)
        {
            Stopwatch sw = new();
            sw.Start();
            if (buffer == null || buffer.Count == 0 || times == null)
            {
                return;
            }
            // 新建缓冲区
            List<ulong> timeArray;// = new List<ulong>((int)microisecondPerMinute);
            List<List<int>> dataArray = [];

            bool canceled = false;

            while (!token.IsCancellationRequested)
            {
                int dataCount = 0;
                //if (times.IsEmpty)
                //{
                //    if (token.IsCancellationRequested)
                //    {
                //        break;
                //    }
                //    Thread.Sleep(100);
                //    continue;
                //}

                // 新建缓冲区
                timeArray = new List<ulong>(dataInfo.BlockSize);
                dataArray = [];
                dataArray.AddRange(from ch in buffer
                                   select new List<int>(dataInfo.BlockSize));
                while (dataCount < dataInfo.BlockSize && !token.IsCancellationRequested)
                {
                    ulong time;
                    if (times.TryDequeue(out time))
                    {
                        timeArray.Add(time);
                        for (int ch = 0; ch < buffer.Count; ch++)
                        {
                            int value = await buffer[ch].Reader.ReadAsync(token);
                            dataArray[ch].Add(value);
                            if (triggers != null && triggers.Length > ch)
                            {
                                if (IsTriggered(value, triggers[ch]))
                                {
                                    triggerCounts[ch]++;
                                }
                            }
                        }
                        dataCount++;
                    }
                    else
                    {
                        await Task.Delay(100);
                    }
                }
                AsyncHelper.RunSync(() => WriteFile(timeArray.ToArray(), dataArray, triggerCounts));
                dataInfo.BlockFileCount++;
                if (dataInfo.BlockFileCount > dataInfo.DayBlockSize)
                {
                    AsyncHelper.RunSync(MergeData);
                    dataInfo.BlockFileCount = 0;
                    dataInfo.DayFileCount++;
                }

                triggerCounts = new int[buffer.Count];
                await Task.Delay(10);
            }

            timeArray = new List<ulong>(dataInfo.BlockSize);
            dataArray = [];
            dataArray.AddRange(from ch in buffer
                               select new List<int>(dataInfo.BlockSize));
            //while (!times.IsEmpty)
            //{
            //    times.TryDequeue(out ulong time);
            //    timeArray.Add(time);
            //    for (int ch = 0; ch < buffer.Count; ch++)
            //    {
            //        buffer[ch].TryDequeue(out int value);
            //        dataArray[ch].Add(value);
            //        if (triggers != null && triggers.Length > ch)
            //        {
            //            if (IsTriggered(value, triggers[ch]))
            //            {
            //                triggerCounts[ch]++;
            //            }
            //        }
            //    }
            //}
            
            //if (timeArray.Count > 0)
            //{
            //    AsyncHelper.RunSync(() => WriteFile(timeArray.ToArray(), dataArray, triggerCounts));
            //}

            Debug.WriteLine($"生成文件耗时{sw.Elapsed.TotalSeconds}s");
            AsyncHelper.RunSync(MergeData);
            sw.Stop();
            Debug.WriteLine($"合并文件耗时{sw.Elapsed.TotalSeconds}s");
        }

        private void AppendChannelProperties(List<ChannelProperty>? properties)
        {
            if (properties == null)
            {
                return;
            }
            var metaData = dataInfo.MetaData;
            if (metaData.Channels == null)
            {
                return;
            }
            if (metaData.Channels.Count != properties.Count)
            {
                return;
            }
            for (int i = 0; i < properties.Count; i++)
            {
                if (metaData.Channels[i].Properties == null)
                {
                    metaData.Channels[i].Properties = [];
                }
                metaData.Channels[i].Properties.Add(properties[i]);
            }
            var bytes = MessagePackSerializer.Serialize(metaData);
            File.WriteAllBytes(Path.Combine(currentTempFileDirectory, ".properties"), bytes);
        }

        private string? GetMetaDataStringFromTempFile()
        {
            try
            {
                var bytes = File.ReadAllBytes(Path.Combine(currentTempFileDirectory, ".properties"));
                return Convert.ToBase64String(bytes);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("元数据读取失败:" + ex.Message);
            }
            return null;
        }

        public int BufferCount => times == null ? 0 : times.Count;
        public async Task WriteFile(ulong[] times, List<List<int>>? datas, int[] triggerCounts)
        {
            if (datas == null || datas.Count == 0 || startTime == null)
            {
                return;
            }

            // 如果目录不存在，则创建目录
            if (!Directory.Exists(currentTempFileDirectory))
            {
                Directory.CreateDirectory(currentTempFileDirectory);
                if (dataInfo.MetaData.Channels != null)
                {
                    foreach (var ch in dataInfo.MetaData.Channels)
                    {
                        ch.Properties?.Clear();
                    }
                }
            }

            List<ChannelProperty> properties = [];
            List<DataField> fields = new();
            //fields.Add(new DataField<ulong>("time"));
            for (int i = 0; i < datas.Count; i++)
            {
                var ch = datas[i];
                properties.Add(new ChannelProperty()
                {
                    Average = ch.Average(),
                    //Sum = ch.Sum(),
                    Max = ch.Max(),
                    Min = ch.Min(),
                    TriggerCount = triggerCounts[i],
                    SampleCount = ch.Count
                });
                fields.Add(new DataField<int>(dataInfo.DataProperty.Channels[i].Name));
            }

            var schema = new ParquetSchema(fields);
            List<DataColumn> columns = [];
            for (int i = 0; i < fields.Count; i++)
            {
                if (i == 0)
                {
                    //columns.Add(new DataColumn(schema.DataFields[0], times));
                }
                else
                {
                    //columns.Add(new DataColumn(schema.DataFields[i], datas[i - 1].ToArray()));
                }
                columns.Add(new DataColumn(schema.DataFields[i], datas[i].ToArray()));
            }

            Debug.WriteLine($"写入Properties:{string.Join(',', properties.Select(p=>p.SampleCount))}");
            AppendChannelProperties(properties);

            using (Stream fileStream = File.OpenWrite(currentTempFilePath))
            {
                using (ParquetWriter parquetWriter = await ParquetWriter.CreateAsync(schema, fileStream))
                {
                    parquetWriter.CompressionMethod = compressionMethod;
                    //parquetWriter.CompressionLevel = System.IO.Compression.CompressionLevel.SmallestSize;

                    // create a new row group in the file
                    using (ParquetRowGroupWriter groupWriter = parquetWriter.CreateRowGroup())
                    {
                        for (int i = 0; i < columns.Count; i++)
                        {
                            await groupWriter.WriteColumnAsync(columns[i]);
                        }
                    }
                }
            }
        }

        private async Task MergeData()
        {
            var metaDataString = GetMetaDataStringFromTempFile();
            if (metaDataString == null)
            {
                return;
            }

            List<FileInfo> files = [];
            DirectoryInfo directoryInfo = new(currentTempFileDirectory);
            foreach (FileInfo item in directoryInfo.EnumerateFiles("*.tmp", SearchOption.AllDirectories))
            {
                files.Add(item);
            }

            using (var merger = new FileMerger(files))
            {
                using (var fs = File.Open(currentFilePath, FileMode.OpenOrCreate))
                {
                    await merger.MergeFilesAsync(fs, compressionMethod: compressionMethod, metadata: new Dictionary<string, string>
                    {
                        ["properties"] = metaDataString
                    });
                }
            }
            Directory.Delete(currentTempFileDirectory, true);
            return;
        }

        public async Task<MetaData?> ReadMetaData(string path)
        {
            Stopwatch sw = new();
            sw.Start();
            if (!Directory.Exists(path))
            {
                return null;
            }
            try
            {
                DirectoryInfo directoryInfo = new(path);
                List<string> files = [];
                foreach (FileInfo item in directoryInfo.EnumerateFiles($"*{extName}", SearchOption.TopDirectoryOnly))
                {
                    files.Add(item.FullName);
                }

                List<MetaData> datas = [];
                foreach (var file in files)
                {
                    using (var fs = File.OpenRead(file))
                    {
                        using (ParquetReader reader = await ParquetReader.CreateAsync(fs))
                        {
                            string str = reader.CustomMetadata["properties"];
                            var bytes = Convert.FromBase64String(str);
                            datas.Add(MessagePackSerializer.Deserialize<MetaData>(bytes));
                        }
                    }
                }
                if (datas.Count == 0)
                {
                    return null;
                }

                MetaData result = new() { StartTime = datas[0].StartTime };
                for (int i = 0; i < datas.Count; i++)
                {
                    var data = datas[i];
                    if (data.Channels == null)
                    {
                        continue;
                    }
                    if (result.Channels == null)
                    {
                        result.Channels = data.Channels;
                    }
                    else
                    {
                        for (int j = 0; j < result.Channels.Count; j++)
                        {
                            ChannelMetaData? ch = result.Channels[j];
                            if (ch.Properties == null)
                            {
                                ch.Properties = [];
                            }
                            var properties = data.Channels[i].Properties;
                            if (properties != null)
                            {
                                ch.Properties.AddRange(properties);
                            }
                        }
                    }
                }
                Debug.WriteLine($"读取元数据耗时：{sw.ElapsedMilliseconds}ms");
                sw.Stop();
                return result;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("元数据读取错误" + ex.Message);
            }
            return null;
        }

        private async Task<double[]> GetTriggerCounts(string file, MetaData metadata, string channelName, TriggerInfo info)
        {
            Debug.WriteLine($"读取{file}");
            using (ParquetReader reader = await ParquetReader.CreateAsync(file))
            {
                int groupCount = reader.RowGroupCount;
                double[] array = new double[groupCount];
                for (int row = 0; row < groupCount; row++)
                {
                    using (var rgr = reader.OpenRowGroupReader(row))
                    {
                        DataField[] datafileds = new DataField[metadata.Channels.Count];
                        //datafileds[0] = new DataField<ulong>("time");
                        for (int i = 0; i < metadata.Channels.Count; i++)
                        {
                            datafileds[i] = new DataField<int>(metadata.Channels[i].Info.Name);
                        }
                        var schema = new ParquetSchema(datafileds);
                        //DataField<ulong> datafield = new DataField<ulong>("time");
                        //foreach (var field in datafileds)
                        {
                            var field = schema.DataFields.FirstOrDefault(s => s.Name == channelName);
                            if (field == null)
                            {
                                throw new Exception("field为null");
                            }
                            var datas = (int[])(await rgr.ReadColumnAsync(field)).Data;
                            int count = 0;
                            //Stopwatch stopwatch = new();
                            //stopwatch.Start();
                            foreach (var data in datas)
                            {
                                if (IsTriggered(data, info))
                                {
                                    count++;
                                }
                            }
                            //stopwatch.Stop();
                            //Debug.WriteLine($"消耗{stopwatch.ElapsedMilliseconds}ms");
                            array[row] = count;
                        }

                    }
                }
                return array;
            }
        }

        public async Task<double[]?> GetTriggerCounts(string? dir, string? channelName, TriggerInfo info)
        {
            if (string.IsNullOrWhiteSpace(dir) || string.IsNullOrWhiteSpace(channelName))
            {
                return null;
            }

            dir = Path.Combine(rootDirectory, dir);

            var metadata = await ReadMetaData(dir);

            if (metadata == null || metadata.Channels == null) return null;
            if (!metadata.Channels.Any(ch => ch.Info.Name == channelName))
            {
                return null;
            }
            try
            {
                Stopwatch sw = new();
                sw.Start();
                DirectoryInfo directoryInfo = new(dir);
                List<string> files = [];
                foreach (FileInfo item in directoryInfo.EnumerateFiles($"*{extName}", SearchOption.TopDirectoryOnly))
                {
                    files.Add(item.FullName);
                }
                if (files.Count == 0) return null;

                var chInfo = metadata.Channels.FirstOrDefault(ch => ch.Info.Name == channelName);
                if (chInfo == null)
                {
                    Debug.WriteLine($"元数据中没有名为{channelName}的列");
                    return null;
                }
                int digits = chInfo.Info.Digits;
                double divider = Math.Pow(10, digits);
                List<int[]> intArrays = new List<int[]>();

                List<double> triggerCounts = [];

                List<Task<double[]>> tasks = [];

                var options = new ParallelOptions
                {
                    MaxDegreeOfParallelism = 1
                };
                //await Parallel.ForEachAsync(files, options, async (file, token) =>
                //{
                //    var result = await GetTriggerCounts(file, metadata, channelName, info);
                //    if (result != null)
                //    {
                //        triggerCounts.AddRange(result);
                //    }
                //});

                foreach (var file in files)
                {
                    var result = await GetTriggerCounts(file, metadata, channelName, info);
                    if (result != null)
                    {
                        triggerCounts.AddRange(result);
                    }
                }

                //foreach (var file in files)
                //{
                //    Debug.WriteLine($"读取{file}");
                //    //tasks.Add(Task.Run(async () =>
                //    {
                //        using (ParquetReader reader = await ParquetReader.CreateAsync(file))
                //        {
                //            int groupCount = reader.RowGroupCount;
                //            double[] array = new double[groupCount];
                //            for (int row = 0; row < groupCount; row++)
                //            {
                //                using (var rgr = reader.OpenRowGroupReader(row))
                //                {
                //                    DataField[] datafileds = new DataField[metadata.Channels.Count];
                //                    //datafileds[0] = new DataField<ulong>("time");
                //                    for (int i = 0; i < metadata.Channels.Count; i++)
                //                    {
                //                        datafileds[i] = new DataField<int>(metadata.Channels[i].Info.Name);
                //                    }
                //                    var schema = new ParquetSchema(datafileds);
                //                    //DataField<ulong> datafield = new DataField<ulong>("time");
                //                    //foreach (var field in datafileds)
                //                    {
                //                        var field = schema.DataFields.FirstOrDefault(s => s.Name == channelName);
                //                        if (field == null)
                //                        {
                //                            throw new Exception("field为null");
                //                        }
                //                        var datas = (int[])(await rgr.ReadColumnAsync(field)).Data;
                //                        int count = 0;
                //                        //Stopwatch stopwatch = new();
                //                        //stopwatch.Start();
                //                        foreach (var data in datas)
                //                        {
                //                            if (IsTriggered(data, info))
                //                            {
                //                                count++;
                //                            }
                //                        }
                //                        //stopwatch.Stop();
                //                        //Debug.WriteLine($"消耗{stopwatch.ElapsedMilliseconds}ms");
                //                        array[row] = count;
                //                    }

                //                }
                //            }
                //            //return array;
                //            triggerCounts.AddRange(array);
                //        }
                //    }
                //    //}));
                //}
                //foreach(var task in tasks)
                //{
                //    triggerCounts.AddRange(task.Result);
                //}
                sw.Stop();
                Debug.WriteLine($"耗时{sw.ElapsedMilliseconds}ms");
                Debug.WriteLine($"总数{triggerCounts.Count}");
                return triggerCounts.ToArray();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            return null;
        }

        public async Task<double[]?> Query(string? dir, string channelName, int blockStart, int blockEnd, MetaData? metadata = null)
        {
            Debug.WriteLine($"查询{blockStart}~{blockEnd}的数据");
            if (blockEnd < blockStart)
            {
                return null;
            }
            if (string.IsNullOrWhiteSpace(dir))
            {
                return null;
            }
            //dir = Path.Combine(rootDirectory, dir);
            if (metadata == null)
            {
                metadata = await ReadMetaData(dir);
                if (metadata == null)
                {
                    return null;
                }
            }
            if (metadata.Channels == null) return null;
            if (!metadata.Channels.Any(ch => ch.Info.Name == channelName))
            {
                return null;
            }
            blockEnd += 1;
            try
            {
                Stopwatch sw = new();
                sw.Start();
                DirectoryInfo directoryInfo = new(dir);
                List<string> files = [];
                foreach (FileInfo item in directoryInfo.EnumerateFiles($"*{extName}", SearchOption.TopDirectoryOnly))
                {
                    files.Add(item.FullName);
                }
                if (files.Count == 0) return null;

                var chInfo = metadata.Channels.FirstOrDefault(ch => ch.Info.Name == channelName);
                if (chInfo == null)
                {
                    Debug.WriteLine($"元数据中没有名为{channelName}的列");
                    return null;
                }
                int digits = chInfo.Info.Digits;
                double divider = Math.Pow(10, digits);
                List<int[]> intArrays = new List<int[]>();

                int startIndex = 0;
                int endIndex = 0;
                foreach (var file in files)
                {
                    //using (var fs = File.OpenRead(file))
                    {
                        using (ParquetReader reader = await ParquetReader.CreateAsync(file))
                        {
                            int groupCount = reader.RowGroupCount;
                            if (blockStart >= groupCount)
                            {
                                blockStart -= groupCount;
                                blockEnd -= groupCount;
                                continue;
                            }
                            Debug.WriteLine($"{groupCount},{blockStart},{blockEnd}");
                            startIndex = blockStart;
                            if (blockEnd >= groupCount)
                            {
                                endIndex = groupCount;
                                blockStart = 0;
                                blockEnd -= groupCount;
                            }
                            else
                            {
                                endIndex = blockEnd;
                            }
                            Debug.WriteLine($"{startIndex}~{endIndex}");
                            for (int row = startIndex; row < endIndex; row++)
                            {
                                using (var rgr = reader.OpenRowGroupReader(row))
                                {
                                    DataField[] datafileds = new DataField[metadata.Channels.Count];
                                    //datafileds[0] = new DataField<ulong>("time");
                                    for (int i = 0; i < metadata.Channels.Count; i++)
                                    {
                                        datafileds[i] = new DataField<int>(metadata.Channels[i].Info.Name);
                                    }
                                    var schema = new ParquetSchema(datafileds);
                                    //DataField<ulong> datafield = new DataField<ulong>("time");
                                    var field = schema.DataFields.FirstOrDefault(s => s.Name == channelName);
                                    if (field == null)
                                    {
                                        continue;
                                    }
                                    var data1 = (int[])(await rgr.ReadColumnAsync(field)).Data;
                                    intArrays.Add(data1);
                                }
                            }
                        }
                    }
                }
                int totalNumber = 0;
                foreach (var array in intArrays)
                {
                    totalNumber += array.Length;
                }

                double[] buffer = new double[totalNumber];
                int index = 0;
                foreach (var array in intArrays)
                {
                    foreach (var val in array)
                    {
                        buffer[index++] = Math.Round((double)val / divider, digits);
                    }
                }
                sw.Stop();
                Debug.WriteLine($"共查询到{totalNumber}个数据");
                Debug.WriteLine($"耗时{sw.ElapsedMilliseconds}ms");
                return buffer;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            return null;
        }

        public async Task CopyFileAsyncWithProgress(string sourcePath, string destinationPath, IProgress<double>? progress = null)
        {
            var files = await Task.Run(() =>
            {
                DirectoryInfo directoryInfo = new(sourcePath);
                List<string> files = [];
                foreach (FileInfo item in directoryInfo.EnumerateFiles($"*{extName}", SearchOption.TopDirectoryOnly))
                {
                    files.Add(item.FullName);
                }
                return files;
            });
            if (files.Count == 0)
            {
                return;
            }
            for (int i = 0; i < files.Count; i++)
            {
                string? file = files[i];
                if (file == null) continue;
                using (FileStream sourceStream = new FileStream(file, FileMode.Open, FileAccess.Read))
                {
                    var temp = Path.Combine(destinationPath, Path.GetFileName(file));
                    Debug.WriteLine(temp);
                    using (FileStream destinationStream = new FileStream(Path.Combine(destinationPath, Path.GetFileName(file)), FileMode.Create, FileAccess.Write))
                    {
                        long fileLength = sourceStream.Length;
                        byte[] buffer = new byte[1024 * 1024]; // 1MB缓冲区，可按需调整
                        int bytesRead;
                        long totalBytesRead = 0;

                        while ((bytesRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                        {
                            await destinationStream.WriteAsync(buffer, 0, bytesRead);
                            totalBytesRead += bytesRead;

                            // 计算并报告进度
                            double progressPercentage = (double)totalBytesRead / fileLength * 100 * (i + 1) / files.Count;
                            progress?.Report(progressPercentage);
                        }
                    }
                }
            }
        }

        public double[] DownSampleArray(double[] rawData, int targetSize)
        {
            int rawDataLength = rawData.Length;
            double[] downsampledArray = new double[targetSize];

            // 计算采样间隔
            int sampleInterval = rawDataLength / targetSize;

            for (int i = 0; i < targetSize; i++)
            {
                // 取每个采样间隔内数据的平均值作为下采样后的值
                int startIndex = i * sampleInterval;
                int endIndex = (i == targetSize - 1) ? rawDataLength : (i + 1) * sampleInterval;

                double sum = 0;
                for (int j = startIndex; j < endIndex; j++)
                {
                    sum += rawData[j];
                }

                downsampledArray[i] = sum / (endIndex - startIndex);
            }

            return downsampledArray;
        }

        private static string EscapeCsvValue(string value)
        {
            if (string.IsNullOrEmpty(value))
                return string.Empty;

            // 如果值包含逗号、引号或换行符，需要用引号括起来
            bool needsQuotes = value.Contains(",") || value.Contains("\"") || value.Contains("\n");

            if (needsQuotes)
            {
                // 替换双引号为两个双引号
                value = value.Replace("\"", "\"\"");
                return $"\"{value}\"";
            }
            return value;
        }

        public async Task ExportData(string dir, List<string> channelNames, int startMinute, int endMinute)
        {
            await Task.Delay(0);
        }
    }
}
